import { useResizeObserver } from '@vueuse/core'
import * as THREE from 'three'
// 常用方法
import { MathUtils } from 'three/src/math/MathUtils'
// 控制器
import { OrbitControls } from 'three/addons/controls/OrbitControls'
import { MapControls } from 'three/addons/controls/MapControls'
import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls'
// 加载器
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader'
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'
// 单击选中模型高亮显示/选中模型发光
// 效果器
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer'
// 渲染器通道
import { RenderPass } from 'three/addons/postprocessing/RenderPass'
import { OutlinePass } from 'three/addons/postprocessing/OutlinePass'
// 着色器通道
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass'
import { FXAAShader } from 'three/addons/shaders/FXAAShader'
// label标签
import { CSS2DObject, CSS2DRenderer } from 'three/addons/renderers/CSS2DRenderer'
import { CSS3DObject, CSS3DRenderer, CSS3DSprite } from 'three/addons/renderers/CSS3DRenderer'

// TWEEN 动画
import { cameraControlsTwwen, cameraTwwen, TWEEN } from './tween'

// 加载器
const GLTFloaderFn = new GLTFLoader()
GLTFloaderFn.setDRACOLoader(new DRACOLoader().setDecoderPath('/three/gltf/'))

// 贴图加载器
const textureLoader = new THREE.TextureLoader()

// 时钟
const clock = new THREE.Clock()

// 场景参数
let keyType = ref('')

/**
 * 创建渲染器
 * @param {dom元素} container
 */
function rendererFn(container) {
	// 渲染器 // antialias开启抗锯齿 alpha开启背景透明
	const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
	renderer.outputColorSpace = THREE.SRGBColorSpace
	renderer.setPixelRatio(window.devicePixelRatio)
	container.value.appendChild(renderer.domElement)
	return renderer
}

/**
 * 创建label渲染器
 * @param {dom元素} container
 */
function labelRendererFn(container, CSS3D = true) {
	let labelRenderer
	if (CSS3D) {
		labelRenderer = new CSS3DRenderer()
	} else {
		labelRenderer = new CSS2DRenderer()
	}
	labelRenderer.domElement.style.position = 'absolute'
	labelRenderer.domElement.style.top = 0
	labelRenderer.domElement.style.pointerEvents = 'none'
	container.value.appendChild(labelRenderer.domElement)
	return labelRenderer
}

// 模型居中显示
function setContent(scene) {
	// 获得包围盒得min和max
	const box = new THREE.Box3().setFromObject(scene)
	// 返回包围盒的中心点
	const center = box.getCenter(new THREE.Vector3())
	scene.position.x += scene.position.x - center.x
	scene.position.y += scene.position.y - center.y
	scene.position.z += scene.position.z - center.z
}

// 打印相机位置和朝向  相机朝向也可以使用 controls.target 获取
function cameraDistanceFn(camera) {
	// 相机朝向
	const distance = camera.position.length()
	const { x, y, z } = camera.position
	const direction = camera.getWorldDirection(new THREE.Vector3())
	const target = new THREE.Vector3(x, y, z).add(direction.multiplyScalar(distance))
	console.log('target', target)
	// 相机位置
	console.log('position', camera.position)
}

// 相机漫游
function cameraFn(camera) {
	/**
	 * 第一人称漫游视角
	 */
	let up = false, //是否向前运行
		down = false, //是否向后运行
		left = false, //是否向左运行
		right = false, //是否向右运行
		keyType = '' // 按钮类型
	document.addEventListener('keydown', keydownFn, false)
	document.addEventListener('keyup', keyupFn, false)

	function keydownFn(event) {
		switch (event.keyCode) {
			case 38: // up
			case 87: // w
				up = true
				keyType = 'up'
				break
			case 37: // left
			case 65: // a
				left = true
				keyType = 'left'
				break
			case 40: // down
			case 83: // s
				down = true
				keyType = 'down'
				break
			case 39: // right
			case 68: // d
				right = true
				keyType = 'right'
				break
		}
	}
	function keyupFn(event) {
		keyType = ''
		switch (event.keyCode) {
			case 38: // up
			case 87: // w
				up = false
				break
			case 37: // left
			case 65: // a
				left = false
				break
			case 40: // down
			case 83: // s
				down = false
				break
			case 39: // right
			case 68: // d
				right = false
				break
		}
	}
	//#region 相机旋转
	let isClicked = false
	document.addEventListener('mousedown', () => {
		isClicked = true
	})
	document.addEventListener('mouseup', () => {
		isClicked = false
	})
	document.addEventListener('mousemove', MouseMove, false)

	let minPolarAngle = 0 // radians
	let maxPolarAngle = Math.PI // radians
	let pointerSpeed = 1.0
	const _PI_2 = Math.PI / 2
	// 欧拉角描述一个旋转变换，通过指定轴顺序和其各个轴向上的指定旋转角度来旋转一个物体。
	const _euler = new THREE.Euler(0, 0, 0, 'YXZ')

	//相机旋转
	function MouseMove(event) {
		event.preventDefault()
		if (!isClicked) return
		const movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0
		const movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0
		_euler.setFromQuaternion(camera.quaternion)
		_euler.y -= movementX * 0.002 * pointerSpeed
		_euler.x += movementY * 0.002 * pointerSpeed
		_euler.x = Math.max(_PI_2 - maxPolarAngle, Math.min(_PI_2 - minPolarAngle, _euler.x))
		camera.quaternion.setFromEuler(_euler)
	}

	// 相机碰撞检测，移动
	let direction = new THREE.Vector3()
	function cameraRender(objects, speed = 0.2) {
		camera.getWorldDirection(direction)
		direction.y = 0
		let position = camera.position.clone()
		if (up) {
			position.add(direction.multiplyScalar(speed))
		}
		if (down) {
			position.add(direction.multiplyScalar(-speed))
		}
		if (left) {
			direction.cross(camera.up)
			position.add(direction.multiplyScalar(-speed))
		}
		if (right) {
			direction.cross(camera.up)
			position.add(direction.multiplyScalar(speed))
		}
		if (!collideCheck(objects, position)) {
			camera.position.set(position.x, position.y, position.z)
		}
		return keyType
	}
	return cameraRender
}

/**
 * objects 障碍物对象
 * position 位置
 * 判断附近有没有障碍物 返回true,false
 */
function collideCheck(objects, position) {
	const arr = [new THREE.Vector3(1, 0, 0), new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 0, 1), new THREE.Vector3(0, 0, -1)]
	for (let i = 0, len = arr.length; i < len; i++) {
		const raycaster = new THREE.Raycaster(position, arr[i], 0, 1)
		const intersections = raycaster.intersectObjects(objects, false)
		if (intersections.length) return true
	}
	return false
}

// 获取模型动画
function mixersFn(object) {
	const animations = object.animations
	const mixer = new THREE.AnimationMixer(object.scene)
	const actions = []
	for (var i = 0; i < animations.length; i++) {
		actions.push(mixer.clipAction(animations[i]))
	}
	actions.forEach((action) => action.play())
	return mixer
}

/**
 * 根据当前相机位置旋转罗盘
 */
function compassRotate(camera) {
	const compass = document.getElementById('compass-pointer')
	if (compass) {
		// 获取相机方向向量 世界坐标 返回一个表示该物体在世界空间中Z轴正方向的矢量。
		const dir = camera.getWorldDirection(new THREE.Vector3()),
			sph = new THREE.Spherical() // 创建球坐标
		// 从Vector3中设置球坐标的radius、phi和theta值。
		sph.setFromVector3(dir)
		// MathUtils.radToDeg 角度转弧度  sph.theta 绕 y (up) 轴的赤道角(方位角)
		compass.style.transform = `rotate(${MathUtils.radToDeg(sph.theta) - 180}deg)`
	}
}

/**
 * 加载网格底图
 */
function initGrid({ scene, size = 3000, step = 300, transparent = true, opacity = 0.5 } = {}) {
	const gridHelper = new THREE.GridHelper(size, step)
	gridHelper.material.transparent = transparent // 是否透明
	gridHelper.material.opacity = opacity // 透明度
	scene.add(gridHelper)
}

export {
	useResizeObserver,
	RGBELoader,
	THREE,
	initGrid,
	MathUtils,
	OrbitControls,
	MapControls,
	FirstPersonControls,
	EffectComposer,
	RenderPass,
	OutlinePass,
	ShaderPass,
	FXAAShader,
	CSS2DObject,
	CSS2DRenderer,
	CSS3DSprite,
	CSS3DObject,
	CSS3DRenderer,
	keyType,
	compassRotate,
	rendererFn,
	labelRendererFn,
	GLTFloaderFn,
	mixersFn,
	clock,
	textureLoader,
	setContent,
	cameraFn,
	collideCheck,
	cameraDistanceFn,
	cameraControlsTwwen,
	cameraTwwen,
	TWEEN
}
